
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <GL/glut.h>
#include <GL/gl.h>
#include <iostream>
#include <fstream>
#include <string>
#include <math.h>

#include "obj.h"


Obj::Obj()
{
	numVertices = 0;
	numTexCoords = 0;
	numNormals = 0;
	numFaces = 0;

	faceVerts = new int[6400*3];

	vertices = new float[6400*3];
	texCoords = new float[6400*3];
	normals = new float[6400*3];

	vertIndices = new int[6400*3];
	texIndices = new int[6400*3];
	normIndices = new int[6400*3];
}
Obj::Obj(std::string filename)
{
	numVertices = 0;
	numTexCoords = 0;
	numNormals = 0;
	numFaces = 0;
	
	faceVerts = new int[6400*3];

	vertices = new float[6400*3];
	texCoords = new float[6400*3];
	normals = new float[6400*3];

	vertIndices = new int[6400*3];
	texIndices = new int[6400*3];
	normIndices = new int[6400*3];
}

void Obj::loadObj( std::string filename )
{
	if(filename.find(".obj") == std::string::npos)
		filename += ".obj";
	fopen_s(&obj, filename.c_str(), "r");

	if(obj==NULL)
	{
		printf("Canot load obj file\n");
		return;
	}

	std::printf("----- Parsing ----- \n");

	char *str = new char[128];
	while(fgets(str, 128, obj))
	{
		if(str[0]=='#') continue;
		if(strstr(str, "v ") != NULL)
			parseVertex(str);
		else if(strstr(str, "vn") != NULL)
			parseNormal(str);
		else if(strstr(str, "vt") != NULL)
			parseTexCoord(str);
		else if(strstr(str, "f ") != NULL)
			parseFace(str);
	}
}

void Obj::parseVertex(char *str)
{
	std::printf("  Vertex %d: ", numVertices);

	int i=0;
	while(str[i]==' ') i++;			//skip preceding whitespace
	i++;							//skip 'v'

	for(int num=0; num<3; num++){
		while(str[i]==' ') i++;			//skip preceding whitespace
		char *val = new char[16];
		int n=0;
		while(str[i]!=' ' && str[i]!='\n')
			val[n++] = str[i++];
		vertices[(numVertices*3)+num] = (float)atof(val);
	}
	std::printf("  %.1f, %.1f, %.1f\n", vertices[(numVertices*3)], vertices[(numVertices*3)+1], vertices[(numVertices*3)+2]);
	numVertices++;
}

void Obj::parseNormal(char *str)
{
	std::printf("  Normal %d: ", numNormals);

	int i=0;
	while(str[i]==' ') i++;	//skip preceding whitespace
	i+=2;					//skip "vn"

	for(int num=0; num<3; num++){
		while(str[i]==' ') i++; //skip preceding whitespace
		char *val = new char[16];
		int n=0;
		while(str[i]!=' ' && str[i]!= '\n')
			val[n++] = str[i++];
		normals[(numNormals*3)+num] = (float)atof(val);
	}
	std::printf("    %.1f, %.1f, %.1f\n", normals[(numNormals*3)], normals[(numNormals*3)+1], normals[(numNormals*3)+2]);
	numNormals++;
}

void Obj::parseTexCoord(char *str)
{
	std::printf("  TexCoord %d: ", numTexCoords);

	int i=0;
	while(str[i]==' ') i++;	//skip preceding whitespace
	i+=2;					//skip "vt"

	for(int num=0; num<3; num++){
		while(str[i]==' ') i++; //skip preceding whitespace
		char *val = new char[16];
		int n=0;
		while(str[i]!=' '&&str[i]!='\n')
			val[n++] = str[i++];
		texCoords[(numTexCoords*2)+num] = (float)atof(val);
	}
	std::printf("    %.1f, %.1f, %.1f\n", texCoords[(numTexCoords*3)], texCoords[(numTexCoords*3)+1], texCoords[(numTexCoords*3)+2]);
	numTexCoords++;
}

void Obj::parseFace(char *str)
{
	std::printf("  Face %d: ", numFaces);

	faceVerts[numFaces] = 0;

	int i=0;
	while(str[i]==' ') i++; //skip preceding whitespace
	i++;					//skip 'f'

	int numV = 0;
	while(str[i]!='\n'){
		while(str[i]==' ') i++;	//skip preceding whitespace
		char *v = new char[8];
		int n=0;
		while(str[i]!='/'){		//get vertex index
			v[n++] = str[i++];
		}
		i++;

		char *vt = new char[8];
		n=0;
		while(str[i]!='/'){		//get texCoord index
			vt[n++] = str[i++];
		}
		vt[n] = '\0';
		i++;

		char *vn = new char[8];
		n=0;
		while(str[i]!=' ' && str[i]!='\n'){		//get normal index
			vn[n++] = str[i++];
		}
		vn[n] = '\0';

		while(str[i]==' ') i++;

		int ind = numFaces*3 + faceVerts[numFaces];

		int valVert = (int)atof(v)-1;
		if(valVert >= 0){
			vertIndices[ind] = valVert;
		} else vertIndices[ind] = -1;
		int valTex = (int)atof(vt)-1;
		if(valTex >= 0){
			texIndices[ind] = valTex;
		} else texIndices[ind] = -1;
		int valNorm = (int)atof(vn)-1;
		if(valNorm >= 0){
			normIndices[ind] = valNorm;
		} else normIndices[ind] = -1;
		faceVerts[numFaces]++;

		std::printf(" %d/%d/%d ", vertIndices[ind], texIndices[ind], normIndices[ind]);

		while(str[i]==' ') i++;	//skip whitespaces (to get to next #/#/# or \n)
	}
	std::printf("\n");
	numFaces++;
}

void Obj::draw()
{
	//std::printf("----- Drawing ----- \n");
	//std::printf(" SIZES: v%d, t%d, n%d, f%d\n", numVertices, numTexCoords, numNormals, numFaces);

	int current = 0;

	for(int f=0; f<numFaces; f++){
		//std::printf("  Face %d\n", f);
		glBegin(GL_POLYGON);
		for(int v=0; v<faceVerts[f]; v++){ 
			char *str = new char[32];

			if (vertIndices[current] != -1){
				int i = vertIndices[current];
				//std::printf("    v%d %.1f, %.1f, %.1f", i, vertices[(i*3)], vertices[(i*3)+1], vertices[(i*3)+2]);
				glVertex3f(vertices[(i*3)], vertices[(i*3)+1], vertices[(i*3)+2]);
			} else std::printf("  ");

			if (texIndices[current] != -1){
				int i = texIndices[current];
				//std::printf("   t%d %.1f, %.1f, %.1f", i, texCoords[(i*3)], texCoords[(i*3)+1], texCoords[(i*3)+2]);
				glTexCoord2f(texIndices[(i*3)], texIndices[(i*3)+1]);
			}

			if (normIndices[current] != -1){
				int i = normIndices[current];
				//std::printf("   n%d %.1f, %.1f, %.1f\n", i, normals[(i*3)], normals[(i*3)+1], normals[(i*3)+2]);
				glNormal3f(normIndices[(i*3)], normIndices[(i*3)+1], normIndices[(i*3)+2]);
			}
			
			current++;
		}
		glEnd();
	}
}

void Obj::printData()
{
	std::printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n");
	std::printf("Vertices:\n");
	for(int i=0; i<numVertices; i++)
		std::printf("	%d: %.2f, %.2f, %.2f\n", i, vertices[(i*3)],vertices[(i*3)+1],vertices[(i*3)+2]);

	std::printf("texCoords:\n");
	for(int i=0; i<numTexCoords; i++)
		std::printf("	%d: %.2f, %.2f, %.2f\n", i, texCoords[(i*3)],texCoords[(i*3)+1],texCoords[(i*3)+2]);
	
	std::printf("Normals:\n");
	for(int i=0; i<numNormals; i++)
		std::printf("	%d: %.2f, %.2f, %.2f\n", i, normals[(i*3)],normals[(i*3)+1],normals[(i*3)+2]);

	int current = 0;
	std::printf("Indices:\n");
	for(int f=0; f<numFaces; f++){
		std::printf("	Face %d:\n", f);
		std::printf("		");
		for(int v=0; v<faceVerts[f]; v++){ 
			char *str = new char[32];

			if (vertIndices[current] != -1) std::printf("%d", vertIndices[current]);
			std::printf("/");
			if (texIndices[current] != -1) std::printf("%d", texIndices[current]);
			std::printf("/");
			if (normIndices[current] != -1) std::printf("%d", normIndices[current]);
			std::printf(" ");
			
			current++;
		}
		std::printf("\n");
	}
}

void objDoubleArrayAllocation(float*& ar, int size)
{
	int newSize = size*2;
	float* newAr = new float[newSize];
	for(int i=0; i<size; i++)
		newAr[i] = (float)ar[i];
	delete [] ar;
}

void objCheckAllocation(float*& ar, int alloc, int num)
{
	if( num+1 == alloc )
		objDoubleArrayAllocation(ar, alloc);
}
